﻿using ModbusTCPLib;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using thinger.DataConvertLib;

namespace ModbusProject
{
    public partial class FrmSiemens : Form
    {
        public FrmSiemens()
        {
            InitializeComponent();
        }

        //创建一个ModbusTCP的通信对象
        private ModbusTCP modbus = new ModbusTCP();

        //当前的连接状态
        private bool isConnected = false;

        //创建取消线程源
        private CancellationTokenSource cts;

        /// <summary>
        /// 建立连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_Connect_Click(object sender, EventArgs e)
        {
            isConnected = modbus.Connect(this.txt_IP.Text.Trim(), Convert.ToInt32(this.txt_Port.Text.Trim()));

            if(isConnected)
            {
                MessageBox.Show("西门子PLC连接成功！", "建立连接");

                cts = new CancellationTokenSource();

                Task.Run(new Action(() =>
                {
                    PLCCommunication();
                }),cts.Token);
            }
            else
            {
                MessageBox.Show("西门子PLC连接失败", "建立连接");
            }
        }

        /// <summary>
        /// 多线程循环执行方法
        /// </summary>
        private void PLCCommunication()
        {
            while(!cts.IsCancellationRequested)
            {
                //从PLC中读取从0开始的86个寄存器，即DB1.DBB0-DB1.DBB171
                byte[] data = modbus.ReadOutputRegisters(0, 86);

                //返回数据满足
                if(data != null && data.Length == 172)
                {
                    try
                    {
                        this.Invoke(new Action(() =>
                        {
                            // 解析
                            UpdateUI(data, this.gb_Read);
                            UpdateUI(data, this.gb_Write);
                        }));
                    }
                    catch (Exception)
                    {
                        break;
                    }
                }
            }
        }

        private void UpdateUI(byte[] data, Control control)
        {
            if(control.HasChildren)
            {
                //遍历容器中所有的Label控件
                foreach(var item in control.Controls.OfType<Label>())
                {
                    //找到Tag有值的控件
                    if(item.Tag != null && item.Tag.ToString().Length > 0)
                    {
                        //将Tag转换成Variable对象
                        var variable = GetVariableByTag(item.Tag.ToString());
                        if(variable != null)
                        {
                            // 根据数据类型做对应的解析
                            switch (variable.VarType)
                            {
                                case DataType.Bool:
                                    item.BackColor = BitLib.GetBitFromByteArray(data, variable.Start, variable.OffsetOrLength)? Color.LimeGreen : Color.Red;
                                    break;
                                case DataType.Byte:
                                    item.Text = ByteLib.GetByteFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.Short:
                                    item.Text = ShortLib.GetShortFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.UShort:
                                    item.Text = UShortLib.GetUShortFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.Int:
                                    item.Text = IntLib.GetIntFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.UInt:
                                    item.Text = UIntLib.GetUIntFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.Float:
                                    item.Text = FloatLib.GetFloatFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.Double:
                                    item.Text = DoubleLib.GetDoubleFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.Long:
                                    item.Text = LongLib.GetLongFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.ULong:
                                    item.Text = ULongLib.GetULongFromByteArray(data, variable.Start).ToString();
                                    break;
                                case DataType.String:
                                    item.Text = StringLib.GetSiemensStringFromByteArray(data, variable.Start, variable.OffsetOrLength);
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 解析控件Tag成Variable对象
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        private Variable GetVariableByTag(string tag)
        {
            if(tag.Contains(';'))
            {
                string[] values = tag.Split(';');

                if(values.Length == 3)
                {
                   try
                    {
                        return new Variable()
                        {
                            VarType = (DataType)Convert.ToInt32(values[0]),
                            Start = Convert.ToInt32(values[1]),
                            OffsetOrLength = Convert.ToInt32(values[2])
                        };
                    }
                    catch(Exception)
                    {
                        return null;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_DisConnect_Click(object sender, EventArgs e)
        {
            if(isConnected)
            {
                cts?.Cancel();
                modbus.DisConnect();
            }
        }

        /// <summary>
        /// 双击修改的事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CommonModify_DoubleClick(object sender, EventArgs e)
        {
            if(sender is Label label)
            {
                if(label.Tag != null && label.Tag.ToString().Length > 0)
                {
                    //原始值
                    string initialValue = label.Text;
                    // Variable对象
                    var variable = GetVariableByTag(label.Tag.ToString());

                    FrmParamSet frmParamSet = new FrmParamSet(initialValue,variable,this.modbus);
                    frmParamSet.ShowDialog();
                }
            }
        }
    }
}
